<script setup lang="ts">
import Quill, { Range } from 'quill'
import 'quill/dist/quill.core.css'
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { debounce } from '../../utils/Utils'
import hljs from 'highlight.js'
import 'highlight.js/styles/vs2015.min.css'
import { link } from 'fs/promises'
//编辑器内容html引用
const editor = ref(null)
//quill实例对象
let quill: Quill
//颜色定义
const colors = {
  enableColor: '#333333', //可用状态颜色
  disableColor: '#888888', //不可用状态颜色
  selectColor: '#540581', //选中颜色
  backgroundColor: '#eeeeee' //选中背景
}
//所有提供的字体颜色
enum Color {
  Black = '#000000',
  Red = '#ff0000',
  Orange = '#ffa500',
  Yellow = '#ffff00',
  Green = '#008000',
  Blue = '#0000ff',
  Purple = '#800080'
}
//段落排列
enum Align {
  Left = '',
  Center = 'center'
}
//列表
enum List {
  Unset = '',
  Order = 'ordered',
  UnSort = 'bullet',
  UnChecked = 'unchecked',
  Checked = 'checked'
}
//文本左边距
enum Indent {
  Left = '-1',
  Right = '+1'
}
//标题
enum Header {
  H1 = 1,
  H2 = 2,
  H3 = 3,
  H4 = 4,
  H5 = 5,
  Unset = 0
}
//当前标题状态
const header = ref(0)
//当前引言状态
const quote = ref(false)
//按钮图标大小
const iconSize = 22
/**
 * 定义视图组件状态
 */
class ViewState {
  enable?: boolean = true
  selected?: boolean = false
  selectable?: boolean = false
  iconColor?: string = colors.enableColor
  backgroundColor?: string = colors.backgroundColor
}
//段落排列只有2种，暂时用不到靠右的
const align = ref('')
//列表 有序 无序 勾选
const list = ref('')
//代码块样式
const code = ref('')
//无状态按钮
const lessState = reactive<ViewState>(new ViewState())
//后退
const returnState = reactive<ViewState>({
  enable: true
})
//前进
const goonState = reactive<ViewState>({
  enable: true
})
//键盘
const keyboard = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: colors.backgroundColor
})
//插入
const insertState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: colors.backgroundColor
})
//段落
const paragraphState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: colors.backgroundColor
})
//文本样式
const textStyleState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: colors.backgroundColor
})
//文本样式
const textTypeState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: colors.backgroundColor
})
//字体加粗状态
const boldState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: 'white'
})
//字体italic状态
const italicState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: 'white'
})
//字体strike状态
const strikeState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: 'white'
})
//字体下划线状态
const underlineState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: 'white'
})
//字体颜色状态
const colorState = reactive<ViewState>({
  enable: true,
  selectable: true,
  backgroundColor: colors.backgroundColor
})
//字体当前颜色
const textColorRef = ref('#000000')

//互斥的按钮，不可同时选中
const radioButtons: ViewState[] = [
  textTypeState,
  textStyleState,
  paragraphState,
  insertState,
  colorState
]
//处理互斥按钮
function radioButtonSelect(buttons: ViewState[], selected: ViewState) {
  for (const state of buttons) {
    if (state !== selected) {
      if (state.selected) {
        state.selected = false
      }
    }
  }
  scrollRectToVisivable()
}
/**
 * 将光标位置滚动到用户可见位置
 */
function scrollRectToVisivable() {
  if (!quill.hasFocus()) {
    return
  }
  const { index, length } = quill.getSelection()
  const bounds = quill.selection.getBounds(index, length)

  if (bounds) {
    nextTick(() => {
      quill.scrollRectIntoView(bounds)
    })
  }
}
/**
 * 返回计算属性：图标当前颜色
 */
function iconColor(state: ViewState) {
  return computed(() => {
    if (!state.enable) {
      return colors.disableColor
    } else {
      if (state.selected) {
        return colors.selectColor
      } else {
        return colors.enableColor
      }
    }
  })
}

/**
 * 键盘按钮
 * @param selected 是否选中
 */
function onKeyboardSelected(selected: boolean) {
  keyboard.selected = selected
  //todo 弹出或隐藏键盘
}
/**
 * 段落按钮
 * @param selected 是否选中
 */
function onParagraphSelected(selected: boolean) {
  paragraphState.selected = selected
  radioButtonSelect(radioButtons, paragraphState)
}
/**
 * 字体样式按钮
 * @param selected 是否选中
 */
function onTextStyleSelected(selected: boolean) {
  textStyleState.selected = selected
  radioButtonSelect(radioButtons, textStyleState)
}
/**
 * 段落边距大小
 * @param direction
 */
function onIndentClick(direction: string) {
  quill.format('indent', direction)
}

/**
 * 标题样式
 */
function onHeaderSelect(selected: boolean, head: number) {
  if (!selected) {
    header.value = 0
    quill.format('header', false)
  } else {
    header.value = head
    quill.format('header', head)
    quill.format('blockquote', false)
    quill.format('code-block', null)
  }
}

/**
 * 引言样式
 */
function onQuoteSelect(selected: boolean) {
  quote.value = selected
  quill.format('blockquote', selected)
  quill.format('header', false)
  quill.format('code-block', null)
}
/**
 * 代码块
 */
function onCodeSelect(selected: boolean) {
  quill.format('blockquote', false)
  quill.format('header', false)
  if (selected) {
    code.value = 'javascript'
    quill.format('code-block', 'javascript')
  } else {
    code.value = ''
    quill.format('code-block', null)
  }
}
/**
 * 文本粗细
 */
function onBoldSelected(selected: boolean) {
  boldState.selected = selected
  if (!quill.hasFocus()) {
    quill.focus()
  }
  quill.format('bold', selected)
}
/**
 * 文本斜体
 * @param selected
 */
function onItalicSelected(selected: boolean) {
  italicState.selected = selected
  if (!quill.hasFocus()) {
    quill.focus()
  }
  quill.format('italic', selected)
}
/**
 * 文本下划线
 * @param selected
 */
function onUnderlineSelected(selected: boolean) {
  underlineState.selected = selected
  if (!quill.hasFocus()) {
    quill.focus()
  }
  quill.format('underline', selected)
}
/**
 * 文本对象线
 * @param selected
 */
function onStrikeSelected(selected: boolean) {
  strikeState.selected = selected
  if (!quill.hasFocus()) {
    quill.focus()
  }
  quill.format('strike', selected)
}

function onColorSelected(selected: boolean) {
  colorState.selected = selected
  radioButtonSelect(radioButtons, colorState)
}
/**
 * @param color 选中的颜色
 */
function onTextColorSelected(color: Color) {
  textColorRef.value = color
  if (!quill.hasFocus()) {
    quill.focus()
  }
  quill.format('color', color)
}
/**
 * @param userAlign 段落重心
 */
function onAlignSelect(userAlign: Align) {
  align.value = userAlign
  if (!quill.hasFocus()) {
    quill.focus()
  }
  if (userAlign == Align.Center) {
    quill.format('align', userAlign)
  } else {
    quill.format('align', '')
  }
}
/**
 * 列表样式选择
 * @param selected 是否选中
 * @param type 列表类型
 */
function onListSelect(selected: boolean, type: string) {
  if (selected) {
    list.value = type
  } else {
    list.value = List.Unset
  }
  quill.format('list', list.value)
}
/**
 * 文本类型按钮
 * @param selected 是否选中
 */
function onTextTypeSelected(selected: boolean) {
  textTypeState.selected = selected
  radioButtonSelect(radioButtons, textTypeState)
  //todo 弹出段落样式
}
/**
 * 插入按钮
 * @param selected 是否选中
 */
function onInsertSelected(selected: boolean) {
  insertState.selected = selected
  radioButtonSelect(radioButtons, insertState)
  //todo 弹出或隐藏键盘
}
/**
 * 清除格式按钮
 */
function onFormatClearClick() {
  if (quill.hasFocus()) {
    if (length == 0) {
      //清除部分文本样式
      quill.format('italic', null)
      quill.format('bold', null)
      quill.format('strike', null)
      quill.format('underline', null)
      quill.format('color', null)
      //手动重置按钮状态
      italicState.selected = false
      boldState.selected = false
      strikeState.selected = false
      underlineState.selected = false
      textColorRef.value = ''
    }
  }
}

const quillOptions = {
  debug: 'info' as 'info',
  placeholder: '编辑内容...',
  modules: {
    syntax: { hljs }
  }
}
function handleSelectionChanged() {
  quill.on('editor-change', () => {
    const range = quill.getSelection()
    if (range) {
      const selectionFormat = quill.getFormat(range)
      checkSelectionStyle(range, selectionFormat)
    }
  })
}
/**
 * 控制链接输入的对话框
 */
const linkDialogModel = reactive({
  show: false, //对话框显示控制
  showTip: false, //显示链接工具框
  url: '' //文本链接地址,
})
const tipRef = ref()
const tipPosition = reactive({
  left: 0,
  top: 0,
  fontSize: 10 + 'px',
  color: 'red'
})
let linkSelectRange: Range //当前选中的文本范围
/**
 * 插入链接
 */
function onInsertLink() {
  const range: Range = quill.getSelection()
  if (range && range.length > 0) {
    quill.blur()
    //有选中的文本,
    linkSelectRange = range
    linkDialogModel.url = ''
    linkDialogModel.show = true
  }
}
/**
 * 用户输入链接
 */
function onAfterInputLink() {
  if (linkDialogModel.url && linkDialogModel.url !== '') {
    //有链接地址
    if (linkSelectRange && linkSelectRange.length > 0) {
      //有选中的文本
      quill.format('link', linkDialogModel.url)
    }
  }
}

/**
 * @param style 当前光标样式
 */
function checkSelectionStyle(range: Range, style: { [format: string]: unknown }) {
  boldState.selected = style['bold'] === true
  italicState.selected = style['italic'] === true
  strikeState.selected = style['strike'] === true
  underlineState.selected = style['underline'] === true
  const textColor = style['color']
  if (textColor && typeof textColor === 'string') {
    textColorRef.value = textColor
  } else {
    textColorRef.value = Color.Black
  }
  const alignValue = style['align']
  if (alignValue && typeof alignValue === 'string' && alignValue == Align.Center) {
    align.value = Align.Center
  } else {
    align.value = Align.Left
  }
  const listValue = style['list']
  if (listValue && typeof listValue === 'string' && listValue !== List.Unset) {
    list.value = listValue
  } else {
    list.value = List.Unset
  }
  const headerValue = style['header']
  if (headerValue && typeof headerValue === 'number' && headerValue !== Header.Unset) {
    header.value = headerValue
  } else {
    header.value = 0
  }
  const quoteValue = style['blockquote']
  if (quoteValue && typeof quoteValue === 'boolean') {
    quote.value = quoteValue
  } else {
    quote.value = false
  }
  const codeBlockValue = style['code-block']
  if (codeBlockValue && typeof codeBlockValue === 'string') {
    code.value = codeBlockValue
  } else {
    code.value = ''
  }

  const linkValue = style['link']
  if (linkValue && typeof linkValue === 'string') {
    //存在链接
    const bounds = quill.getBounds(range)
    linkDialogModel.url = linkValue
    linkDialogModel.showTip = true

    //计算位置，防止弹窗超过屏幕导致发生横向滚动
    const tipWidth = 260
    const userVisivableWidth = window.innerWidth
    tipPosition.left = Math.max(0, Math.min(bounds.left, userVisivableWidth - tipWidth))
    tipPosition.top = bounds.bottom + 60
  } else {
    linkDialogModel.url = ''
    linkDialogModel.showTip = false
  }
}

function handleSizeChanged() {
  scrollRectToVisivable()
}
/**
 * 挂载组件
 */
onMounted(() => {
  //实例化编辑器
  quill = new Quill(editor.value as HTMLElement, quillOptions)
  //监听光标变化
  handleSelectionChanged()
  //监听视图尺寸变化 变化后如果光标不可见说明需要滚动
  window.addEventListener('resize', debounce(handleSizeChanged, 500))
})
/**
 * 取消挂载前回调
 */
onBeforeUnmount(() => {
  //移除尺寸监听
  window.removeEventListener('resize', debounce(handleSizeChanged, 500))
})
</script>
<template>
  <var-dialog @confirm="onAfterInputLink" v-model:show="linkDialogModel.show">
    <template #title>
      <div>插入链接</div>
    </template>
    <var-input
      type="text"
      placeholder="输入链接地址"
      :rules="[(v) => !!v || '不能为空', (v) => v.length >= 1 || '不能为空']"
      v-model="linkDialogModel.url"
    />
  </var-dialog>

  <div class="root-container">
    <div class="top-bar">
      <StatefullButton alt="关闭按钮" :state="lessState">
        <IconClose :color="colors.enableColor" :width="iconSize" :height="iconSize"></IconClose>
      </StatefullButton>

      <StatefullButton alt="后退按钮" :state="returnState">
        <IconReturn
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(returnState).value"
        ></IconReturn>
      </StatefullButton>
      <StatefullButton alt="前进按钮" :state="goonState">
        <IconGoon
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(goonState).value"
        ></IconGoon>
      </StatefullButton>
      <div style="flex-grow: 1"></div>
      <StatefullButton alt="目录按钮" :state="lessState">
        <IconMenu :width="iconSize" :height="iconSize" :color="colors.enableColor"></IconMenu>
      </StatefullButton>
      <StatefullButton alt="保存按钮" :state="lessState">
        <IconSave :width="iconSize" :height="iconSize" :color="colors.enableColor"></IconSave>
      </StatefullButton>
    </div>
    <div ref="editor" class="container">
      长安大道连狭斜，青牛白马七香车。 玉辇纵横过主第，金鞭络绎向侯家。
      龙衔宝盖承朝日，凤吐流苏带晚霞。 百尺游丝争绕树，一群娇鸟共啼花。
      游蜂戏蝶千门侧，碧树银台万种色。 复道交窗作合欢，双阙连甍垂凤翼。
      梁家画阁中天起，汉帝金茎云外直。 楼前相望不相知，陌上相逢讵相识？
      借问吹箫向紫烟，曾经学舞度芳年。 得成比目何辞死，愿作鸳鸯不羡仙。
      比目鸳鸯真可羡，双去双来君不见？
    </div>

    <div class="bottom-sub-bar-container">
      <div v-show="insertState.selected" alt="插入内容子选项" class="bottom-sub-bar">
        <StatefullButton alt="插入链接" :state="lessState" @click="onInsertLink">
          <IconLink :width="iconSize" :height="iconSize" :color="colors.enableColor"></IconLink>
        </StatefullButton>
        <StatefullButton alt="插入图片" :state="lessState">
          <IconImage :width="iconSize" :height="iconSize" :color="colors.enableColor"></IconImage>
        </StatefullButton>
        <StatefullButton alt="插入视频" :state="lessState">
          <IconVideo :width="iconSize" :height="iconSize" :color="colors.enableColor"></IconVideo>
        </StatefullButton>
        <StatefullButton alt="插入音频" :state="lessState">
          <IconVoice :width="iconSize" :height="iconSize" :color="colors.enableColor"></IconVoice>
        </StatefullButton>
      </div>

      <div v-show="paragraphState.selected" alt="段落样式子选项" class="bottom-sub-bar">
        <CheckStatefullButton
          alt="无序列表"
          :select="list == List.UnSort"
          @select="
            (seleted: boolean) => {
              onListSelect(seleted, List.UnSort)
            }
          "
        >
          <IconListUnOrder
            :width="iconSize"
            :height="iconSize"
            :color="list == List.UnSort ? colors.selectColor : colors.enableColor"
          ></IconListUnOrder>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="有序列表"
          :select="list == List.Order"
          @select="
            (seleted: boolean) => {
              onListSelect(seleted, List.Order)
            }
          "
        >
          <IconListOrder
            :width="iconSize"
            :height="iconSize"
            :color="list == List.Order ? colors.selectColor : colors.enableColor"
          ></IconListOrder>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="代办列表"
          :select="list == List.Checked || list == List.UnChecked"
          @select="
            (seleted: boolean) => {
              onListSelect(seleted, List.UnChecked)
            }
          "
        >
          <IconListCheck
            :width="iconSize"
            :height="iconSize"
            :color="
              list == List.Checked || list == List.UnChecked
                ? colors.selectColor
                : colors.enableColor
            "
          ></IconListCheck>
        </CheckStatefullButton>
        <StatefullButton alt="右缩进" :state="lessState" @click="onIndentClick(Indent.Right)">
          <IconIndentRight
            :width="iconSize"
            :height="iconSize"
            :color="colors.enableColor"
          ></IconIndentRight>
        </StatefullButton>
        <StatefullButton alt="左缩进" :state="lessState" @click="onIndentClick(Indent.Left)">
          <IconIndentLeft
            :width="iconSize"
            :height="iconSize"
            :color="colors.enableColor"
          ></IconIndentLeft>
        </StatefullButton>
        <CheckStatefullButton
          @select="onAlignSelect(Align.Left)"
          alt="居左"
          :select="align == Align.Left"
        >
          <IconAlignLeft
            :width="iconSize"
            :height="iconSize"
            :color="align == Align.Left ? colors.selectColor : colors.enableColor"
          ></IconAlignLeft>
        </CheckStatefullButton>
        <CheckStatefullButton
          @select="onAlignSelect(Align.Center)"
          alt="居中"
          :select="align == Align.Center"
        >
          <IconAlignCenter
            :width="iconSize"
            :height="iconSize"
            :color="align == Align.Center ? colors.selectColor : colors.enableColor"
          ></IconAlignCenter>
        </CheckStatefullButton>
      </div>

      <div v-show="textTypeState.selected" alt="文本类型子选项" class="bottom-sub-bar">
        <CheckStatefullButton
          alt="H1"
          :select="header == Header.H1"
          @select="(selected) => onHeaderSelect(selected, Header.H1)"
        >
          <IconH1
            :width="iconSize"
            :height="iconSize"
            :color="header == Header.H1 ? colors.selectColor : colors.enableColor"
          ></IconH1>
        </CheckStatefullButton>

        <CheckStatefullButton
          alt="H2"
          :select="header == Header.H2"
          @select="(selected) => onHeaderSelect(selected, Header.H2)"
        >
          <IconH2
            :width="iconSize"
            :height="iconSize"
            :color="header == Header.H2 ? colors.selectColor : colors.enableColor"
          ></IconH2>
        </CheckStatefullButton>

        <CheckStatefullButton
          alt="H3"
          :select="header == Header.H3"
          @select="(selected) => onHeaderSelect(selected, Header.H3)"
        >
          <IconH3
            :width="iconSize"
            :height="iconSize"
            :color="header == Header.H3 ? colors.selectColor : colors.enableColor"
          ></IconH3>
        </CheckStatefullButton>

        <CheckStatefullButton
          alt="H4"
          :select="header == Header.H4"
          @select="(selected) => onHeaderSelect(selected, Header.H4)"
        >
          <IconH4
            :width="iconSize"
            :height="iconSize"
            :color="header == Header.H4 ? colors.selectColor : colors.enableColor"
          ></IconH4>
        </CheckStatefullButton>

        <CheckStatefullButton
          alt="H5"
          :select="header == Header.H5"
          @select="(selected) => onHeaderSelect(selected, Header.H5)"
        >
          <IconH5
            :width="iconSize"
            :height="iconSize"
            :color="header == Header.H5 ? colors.selectColor : colors.enableColor"
          ></IconH5>
        </CheckStatefullButton>

        <CheckStatefullButton alt="引言" :select="quote" @select="onQuoteSelect">
          <IconQuote
            :width="iconSize"
            :height="iconSize"
            :color="quote ? colors.selectColor : colors.enableColor"
          ></IconQuote>
        </CheckStatefullButton>
        <CheckStatefullButton alt="代码" :select="code != ''" @select="onCodeSelect">
          <IconCode
            :width="iconSize"
            :height="iconSize"
            :color="code !== '' ? colors.selectColor : colors.enableColor"
          ></IconCode>
        </CheckStatefullButton>
      </div>
      <div v-show="textStyleState.selected" alt="文本样式" class="bottom-sub-bar">
        <StatefullButton alt="粗体" :state="boldState" @select="onBoldSelected">
          <IconBold
            :width="iconSize"
            :height="iconSize"
            :color="iconColor(boldState).value"
          ></IconBold>
        </StatefullButton>
        <StatefullButton alt="斜体" :state="italicState" @select="onItalicSelected">
          <IconItalic
            :width="iconSize"
            :height="iconSize"
            :color="iconColor(italicState).value"
          ></IconItalic>
        </StatefullButton>
        <StatefullButton alt="对象线" :state="strikeState" @select="onStrikeSelected">
          <IconStrike
            :width="iconSize"
            :height="iconSize"
            :color="iconColor(strikeState).value"
          ></IconStrike>
        </StatefullButton>
        <StatefullButton alt="下划线" :state="underlineState" @select="onUnderlineSelected">
          <IconUnderline
            :width="iconSize"
            :height="iconSize"
            :color="iconColor(underlineState).value"
          ></IconUnderline>
        </StatefullButton>
      </div>
      <div v-show="colorState.selected" alt="取色盘，只用于文本取色" class="bottom-sub-bar">
        <CheckStatefullButton
          alt="黑色"
          :select="textColorRef == Color.Black"
          @select="onTextColorSelected(Color.Black)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Black"></IconSquare>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="红色"
          :select="textColorRef == Color.Red"
          @select="onTextColorSelected(Color.Red)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Red"></IconSquare>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="橙色"
          :select="textColorRef == Color.Orange"
          @select="onTextColorSelected(Color.Orange)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Orange"></IconSquare>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="黄色"
          :select="textColorRef == Color.Yellow"
          @select="onTextColorSelected(Color.Yellow)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Yellow"></IconSquare>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="绿色"
          :select="textColorRef == Color.Green"
          @select="onTextColorSelected(Color.Green)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Green"></IconSquare>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="蓝色"
          :select="textColorRef == Color.Blue"
          @select="onTextColorSelected(Color.Blue)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Blue"></IconSquare>
        </CheckStatefullButton>
        <CheckStatefullButton
          alt="紫色"
          :select="textColorRef == Color.Purple"
          @select="onTextColorSelected(Color.Purple)"
        >
          <IconSquare :width="iconSize" :height="iconSize" :color="Color.Purple"></IconSquare>
        </CheckStatefullButton>
      </div>
    </div>

    <div class="bottom-bar">
      <StatefullButton alt="键盘按钮" :state="keyboard" @select="onKeyboardSelected">
        <IconKeyboard
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(keyboard).value"
        ></IconKeyboard>
      </StatefullButton>

      <StatefullButton alt="文本样式按钮" :state="textStyleState" @select="onTextStyleSelected">
        <IconTextStyle
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(textStyleState).value"
        ></IconTextStyle>
      </StatefullButton>

      <StatefullButton alt="文本类型按钮" :state="textTypeState" @select="onTextTypeSelected">
        <IconTextType
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(textTypeState).value"
        ></IconTextType>
      </StatefullButton>

      <StatefullButton alt="段落样式按钮" :state="paragraphState" @select="onParagraphSelected">
        <IconTextAlign
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(paragraphState).value"
        ></IconTextAlign>
      </StatefullButton>
      <StatefullButton alt="颜色" :state="colorState" @select="onColorSelected">
        <IconColor
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(colorState).value"
        ></IconColor>
      </StatefullButton>

      <div style="flex-grow: 1"></div>

      <StatefullButton alt="插入按钮" :state="insertState" @select="onInsertSelected">
        <IconInsert
          :width="iconSize"
          :height="iconSize"
          :color="iconColor(insertState).value"
        ></IconInsert>
      </StatefullButton>

      <StatefullButton alt="清除格式按钮" :state="lessState" @click="onFormatClearClick">
        <IconFormatClear
          :width="iconSize"
          :height="iconSize"
          :color="colors.enableColor"
        ></IconFormatClear>
      </StatefullButton>
    </div>

    <div
      ref="tipRef"
      v-show="linkDialogModel.showTip"
      class="tips"
      :style="{ left: tipPosition.left + 'px', top: tipPosition.top + 'px' }"
    >
      <a target="_blank" :href="linkDialogModel.url">{{ linkDialogModel.url }}</a>
      <div></div>
      <span>编辑</span>
      <div></div>
      <span>移除</span>
    </div>
  </div>
</template>

<style scoped>
.root-container {
  display: -webkit-flex;
  display: flex;
  flex-direction: column;
  height: 100vh;
}
.top-bar {
  padding: 2px 8px;
  border-bottom: 0.5px solid #eeeeee;
  display: flex;
  align-items: center;
  flex-direction: row;
}
.container {
  flex-grow: 1;
  overflow-y: auto;
  padding: 10px 12px;
  font-size: 16px;
  line-height: 1.5;
}
.container::-webkit-scrollbar {
  width: 0;
}
.root-container .tips {
  display: flex;
  align-items: center;
  left: 100px;
  top: 200px;
  box-shadow: 0px 0px 2px #eeeeee;
  position: absolute;
  border: 0.5px solid #eeeeee;
  background: #eeeeee;
  border-radius: 8px;
  padding: 4px 12px;
  text-align: center;
}
.tips div {
  margin: 0px 4px;
  border-radius: 2px;
  background: #00000031;
  width: 2px;
  height: 10px;
}
.tips span,
a {
  font-size: 14px;
  color: #23241f;
}
.tips a {
  white-space: nowrap;
  max-width: 140px;
  overflow: hidden;
}
.bottom-sub-bar-container {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: white;
}
.bottom-sub-bar {
  margin: 2px 0px;
  box-shadow: 0px 0px 2px #eeeeee;
  border-radius: 4px;
  border: 0.5px solid #eeeeee;
  display: flex;
  align-items: center;
  flex-direction: row;
}
.bottom-sub-bar::-webkit-scrollbar {
  width: 0;
}
.bottom-bar {
  padding: 2px 8px;
  border-top: 0.5px solid #eeeeee;
  display: flex;
  align-items: center;
  flex-direction: row;
}
:deep(.ql-editor) {
  min-height: 200px;
  padding: 8px 8px;
  outline: 0.5px solid #eeeeee66;
  background: #eeeeee33;
  border: 0.5px solid #f7f7f766;
  border-radius: 8px;
  font-family: 'icomoon';
}
:deep(.ql-editor .ql-code-block-container) {
  background-color: #23241f;
  color: #f8f8f2;
  overflow: visible;
  margin-bottom: 5px;
  margin-top: 5px;
  padding: 5px 10px;
  border-radius: 3px;
  position: relative;
  box-sizing: border-box;
}
:deep(.ql-code-block-container .ql-ui) {
  right: 5px;
  top: 5px;
}
:deep(.ql-editor li[data-list='unchecked'] > .ql-ui:before) {
  content: '\e900';
  font-family: 'icomoon';
}
:deep(.ql-editor li[data-list='checked'] > .ql-ui:before) {
  content: '\e901';
  font-family: 'icomoon';
}
:deep(.container p) {
  margin-block-start: 0.2em;
  margin-block-end: 0.2em;
}
:deep(.ql-editor blockquote) {
  border-left: 4px solid #eeeeee;
  border-radius: 4px;
  padding-left: 16px;
  margin-bottom: 4px;
  margin-top: 4px;
}
@font-face {
  font-family: 'icomoon';
  src: url('../../assets/fonts/icomoon.eot?sztn4h');
  src:
    url('../../assets/fonts/icomoon.eot?sztn4h#iefix') format('embedded-opentype'),
    url('../../assets/fonts/icomoon.ttf?sztn4h') format('truetype'),
    url('../../assets/fonts/icomoon.woff?sztn4h') format('woff'),
    url('../../assets/fonts/icomoon.svg?sztn4h#icomoon') format('svg');
  font-weight: normal;
  font-style: normal;
  font-display: block;
}
</style>
